/*
 *  bodypart.cpp
 *  bgsubtraction
 *
 *  Created by a1gucis on 4/5/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */

#include "bodypart.h"
BodyPart::BodyPart(int nClusters) {
	this->nClusters = nClusters;
	this->originalImage = NULL;
	this->labeledImage = NULL;
	this->bgLabel = -1;
	this->em = new EM();
	this->kmeans = new KMeans(nClusters);
	this->em->setClusters(nClusters);
	this->clusterFusion = new ClusterFusion();
	
}

BodyPart::~BodyPart() {
	delete em;
	cvReleaseImage(&originalImage);
	cvReleaseImage(&labeledImage);
	cvReleaseImage(&trainImage);
}

void BodyPart::setOriginalImage(IplImage *image) {
	this->originalImage = image;
	if (labeledImage == NULL) 
		this->labeledImage = cvCreateImage(cvSize(image->width, image->height), IPL_DEPTH_8U, 1);
}

void BodyPart::setTrainImage(IplImage *image) {
	this->trainImage = image;
	//CvMat *mat = cvCreateMat(image->height, image->width, CV_32FC3);
	//Utils::PrintDImg(trainImage);
}

void BodyPart::train(bool imageSizeChanged) {
	//Utils::PrintDImg(trainImage);
	em->train(this->trainImage, imageSizeChanged);
}

void BodyPart::setLabels() {
	//cout<<"MEANS: "<<endl;
	//const CvMat *mat = em->get_means();
	//Utils::PrintMat(mat);
	//cout<<"####################"<<endl;
	kmeans->predict(this->originalImage, this->labeledImage);
	//em->predict(this->originalImage, this->labeledImage);
	//clusterFusion->fuse(this->labeledImage, mopCloseIterations);
	//clusterFusion->fuse(this->labeledImage, );
	this->bgLabel = findBgLabel(BG_LABEL_MATRIX_SIZE);
	//clusterFusion->fuse(this->labeledImage, this->bgLabel, 7);
}

void BodyPart::setBgLabel(int label) {
	this->bgLabel = label;
}

bool BodyPart::isBlob(int row, int col, int neighbourhood) {
	uchar *data = (uchar *)labeledImage->imageData;
	data += row*labeledImage->widthStep+col*labeledImage->nChannels;
	int label = (int) *data;
	if (label == bgLabel)
		return false;
	
	bool isBlob = true;
	for (int i=0;i<neighbourhood;i++) {
		for (int j=0;j<neighbourhood;j++) {
			if (data[i*labeledImage->widthStep+j*labeledImage->nChannels] != label)
				isBlob = false;
		}
		
	}
	
	return isBlob;
}
int BodyPart::findBgLabel(int neighbourhood) {
	int maxLabel = -1;
	Clusters *clusters = new Clusters();
	uchar *data = (uchar *)labeledImage->imageData;
	//top left corner
	for (int i=0;i<neighbourhood;i++) {
		for (int j=0;j<neighbourhood;j++) {
			int label = (int)data[i*labeledImage->widthStep + j*labeledImage->nChannels];
			clusters->addLabel((int)label);
		}
	}
	/*
	//top right corner
	for (int i=0;i<neighbourhood;i++) {
		for (int j=0;j<neighbourhood;j++) {
			uchar label = data[i*labeledImage->widthStep + labeledImage->width - j*labeledImage->nChannels];
			clusters->addLabel((int)label);
		}
	}

	//bottom left corner
	for (int i=0;i<neighbourhood;i++) {
		for (int j=0;j<neighbourhood;j++) {
			uchar label = data[(labeledImage->height-1)*labeledImage->widthStep - i*labeledImage->widthStep + j*labeledImage->nChannels];
			clusters->addLabel((int)label);
		}
	}
	
	//bottom right corner
	for (int i=0;i<neighbourhood;i++) {
		for (int j=0;j<neighbourhood;j++) {
			uchar label = data[(labeledImage->height-1)*labeledImage->widthStep - i*labeledImage->widthStep + labeledImage->widthStep-1 - j*labeledImage->nChannels];
			clusters->addLabel((int)label);
		}
	}
	 */
	maxLabel = clusters->getMaxLabel();
	delete clusters;
	return maxLabel;
}

int BodyPart::getBgLabel() {
	return this->bgLabel;
}

IplImage* BodyPart::getLabeledImage() {
	return this->labeledImage;
}

IplImage* BodyPart::getOriginalImage() {
	return this->originalImage;
}

//debug purposes
void BodyPart::test() {
	IplImage *testImage = cvLoadImage("./simpson2Gray.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	cvNamedWindow("test", CV_WINDOW_AUTOSIZE);
	cvShowImage("test", testImage);
	this->labeledImage = testImage;
	cout<<"BG LABEL: "<<findBgLabel(3)<<endl;
	if (isBlob(10, 184, 7))
		cout<<"IT IS A BLOB"<<endl;
	else
		cout<<"NOT A BLOB"<<endl;
	while (1) {
		char c = cvWaitKey(25);
		if (c == 27)
			break;
	}
	
	cvReleaseImage(&testImage);
	cvDestroyWindow("test");
	//this->labeledImage = testImage;
}



